package com.github.shiqiyue.myadmin.config.syslog.aspect;

import com.github.shiqiyue.myadmin.config.syslog.anontation.SysLog;
import com.github.shiqiyue.myadmin.entity.SessionUser;
import com.github.shiqiyue.myadmin.entity.system.SysLogRecord;
import com.github.shiqiyue.myadmin.service.system.syslog.SysLogService;
import com.github.shiqiyue.myadmin.util.json.JsonUtils;
import com.github.shiqiyue.myadmin.util.security.SecurityUtils;
import com.github.shiqiyue.myadmin.util.web.IpUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.InputStreamSource;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;

/***
 * 系统日志切面
 *
 * @author wwy
 *
 */
@Aspect
public class SysLogAspect {

    private SysLogService sysLogService;

    private ThreadLocal<SysLogRecord> sysLogRecordMap = new ThreadLocal<>();

    private ThreadLocal<SysLog> sysLogAnnotationMap = new ThreadLocal<>();


    /***
     * 请求参数最大长度，超过则不处理
     */
    private Integer maxRequsetParamLength = Integer.MAX_VALUE;


    /***
     * 返回参数最大长度，超过则不处理
     */
    private Integer maxResponseParamLength = Integer.MAX_VALUE;

    private static final Logger LOG = LoggerFactory.getLogger(SysLogAspect.class);


    @Pointcut("@annotation(com.github.shiqiyue.myadmin.config.syslog.anontation.SysLog)")
    public void webLog() {
    }

    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) {
        try {
            // 接收到请求，记录请求内容
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
                    .getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            SysLogRecord sysLogRecord = new SysLogRecord();
            SysLog syslog = AnnotationUtils.findAnnotation(method, SysLog.class);

            // 注解上的描述
            sysLogRecord.setOperation(syslog.value());
            sysLogAnnotationMap.set(syslog);


            // 记录下请求内容
            sysLogRecord.setIp(IpUtils.getIpAddr(request));
            sysLogRecord.setMethod(joinPoint.getSignature().getDeclaringTypeName() + "."
                    + joinPoint.getSignature().getName() + ":" + request.getMethod());

            // 记录请求参数
            Object[] args = joinPoint.getArgs();
            if (!syslog.ignoreResquestParams() && args != null && args.length > 0) {
                StringBuffer paramsBuffer = new StringBuffer();
                for (int i = 0; i < args.length; i++) {
                    Object arg = args[i];
                    if (arg instanceof HttpSession) {
                        paramsBuffer.append("param[").append(i).append("]:httpsession,");
                    } else if (arg instanceof HttpServletRequest) {
                        paramsBuffer.append("param[").append(i).append("]:HttpServletRequest,");
                    } else if (arg instanceof HttpServletResponse) {
                        paramsBuffer.append("param[").append(i).append("]:HttpServletResponse,");
                    } else if (arg instanceof InputStreamSource) {
                        paramsBuffer.append("param[").append(i).append("]:file,");
                    } else {
                        String argJson = JsonUtils.beanToString(arg);
                        if (argJson.length() < maxRequsetParamLength)
                            paramsBuffer.append("param[").append(i).append("]:").append(JsonUtils.beanToString(arg))
                                    .append(",");
                    }
                }
                sysLogRecord.setParams(paramsBuffer.toString());
            }
            sysLogRecord.setTime(System.currentTimeMillis());
            SessionUser sessionUser = SecurityUtils.getSessionUser();
            if (sessionUser != null) {
                sysLogRecord.setUserId(sessionUser.getUser().getId());
                sysLogRecord.setUsername(sessionUser.getUsername());
            }
            sysLogRecordMap.set(sysLogRecord);
        } catch (Exception e) {
            LOG.error("处理系统日志出现异常", e);
        }

    }

    @AfterReturning(returning = "ret", pointcut = "webLog()")
    public void doAfterReturning(Object ret) throws Throwable {
        try {
            SysLogRecord sysLogRecord = sysLogRecordMap.get();
            SysLog sysLog = sysLogAnnotationMap.get();
            String response = JsonUtils.beanToString(ret);
            if (!sysLog.ignoreResponseParams() && response.length() < maxResponseParamLength) {
                sysLogRecord.setResponse(response);
            }
            sysLogRecord.setTime(System.currentTimeMillis() - sysLogRecord.getTime());
            sysLogService.insert(sysLogRecord);

        } catch (Exception e) {
            LOG.error("处理系统日志出现异常", e);
        } finally {
            sysLogRecordMap.remove();
            sysLogAnnotationMap.remove();
        }

    }

    @AfterThrowing(pointcut = "webLog()")
    public void afterThrowing() {
        sysLogRecordMap.remove();
        sysLogAnnotationMap.remove();
    }

    public void setSysLogService(SysLogService sysLogService) {
        this.sysLogService = sysLogService;
    }

    public void setMaxResponseParamLength(Integer maxResponseParamLength) {
        this.maxResponseParamLength = maxResponseParamLength;
    }

    public void setMaxRequsetParamLength(Integer maxRequsetParamLength) {
        this.maxRequsetParamLength = maxRequsetParamLength;
    }
}